package com.cloud.netty.codec;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;

public class NettyServer {


    public static void main(String[] args) throws InterruptedException {
        // 创建BossGroup 和 workGroup
        // 说明
        // 1.创建两个线程组bossGroup 和 workGroup
        // 2.bossGroup 只有处理连接请求，真正的和客户端业务处理，会交给
        // 3.两个都是无线循环
        // 默认cpu核数乘以2 我的电脑是16线程，则children默认会有32个子线程
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            // 创建服务器短的启动对象，配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();

            // 使用链式编程来进行设置
            bootstrap.group(bossGroup,workGroup) // 设置两个线程组
                    .channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG,128) // 设置线程队列得到连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE,true) // 设置保持活动连接状态
                    .handler(null) // 该handler 对应bossGroup childHandler 对应workGroup
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        // 给pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 可以使用一个集合管理socketChannel，再推送消息时，可以将业务加入到各个channel
                            // 对应的NioEventLoop的taskQueue或者scheduleTaskQueue
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new NettyServerHandler());
                            // 需要指定对哪种对象进行解码
                            pipeline.addLast("decoder",new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));
                        }
                    });
            // 给我们的workgroup和eventloop对应的管道设置处理器
            System.out.println("....服务器 is ready...");

            // 绑定一个端口并同步处理，生成一个channelFuture对象
            final ChannelFuture cf = bootstrap.bind(6668).sync();

            // 给cf注册监听器 监控我们关心的事件
            cf.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (cf.isSuccess()) {
                        System.out.println("监听端口6668成功！");
                    } else {
                        System.out.println("监听端口6668失败！");
                    }
                }
            });

            // 对关闭通道进行监听
            cf.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
        }

    }
}
